package socket.auction.server;
import java.io.*;
import java.net.*;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.Registry;
import java.util.ArrayList;
import java.util.NoSuchElementException;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.log4j.Logger;

import rmi.analytics.server.AnalyticsInterface;
import rmi.analytics.server.AnalyticsServer;
import rmi.billing.exceptions.LoginFailedRemoteException;
import rmi.billing.server.BillingServerInterface;
import rmi.billing.server.BillingServerSecure;
import rmi.domain.RegistrySingleton;
import rmi.domain.RemoteRegistrySingleton;


class Server implements Runnable {
	public static Logger log = Logger.getLogger(Server.class);
	
	private ExecutorService executor = Executors.newCachedThreadPool();

	private static ServerSocket s;
	//UserDB
	private UserDB userdb = new UserDB();
	//AuktionsDB
	private AuctionManager auct = new AuctionManager();
	//SessionDB
	private ArrayList<ClientSession> sessionDB = new ArrayList<ClientSession>();
	
	private AnalyticsInterface analyticsServ = null;
	
	//Constructor
	public Server(int tcpport, String analyticsBindingName, String billingBindingName){
		try {		
			
			//Registry
			
			Registry reg=null;
			try {
				reg = RemoteRegistrySingleton.getRemoteRegistry();
			} catch (RemoteException e1) {
				System.out.println("Can't get RemoteRegistry with given properties!");
				System.out.println("..as well Analyticpart as Billingpart won't work!...");
				
			}
			
			//AnalyticsServer			     
			if (!(reg==null)){
				try {
					analyticsServ =(AnalyticsInterface) reg.lookup(analyticsBindingName); // args[1]
					auct.setAnalytics(analyticsServ);
				} catch (RemoteException e) {
					log.error("ERROR: Connecting to AnalyticsServer ");
				} catch (NotBoundException e) {				
					log.error("AuctionServer has not been started ");
				}
			}

					
			
			
			//login to BillingServer
			
	        BillingServerInterface billServ;	
	        BillingServerSecure billSecure = null;
			
	        if (!(reg==null)){
				try {
					billServ =(BillingServerInterface) reg.lookup(billingBindingName); // args[2]
				    billSecure =   billServ.login("auctionClientUser", "dslab2012");
				    log.info("AuctionServer successfully logged in to BillingServer!");
				    auct.setBillSecure(billSecure);
				} catch (RemoteException e) {
					log.error("Error Login AuctionClient ");
				} catch (NotBoundException e) {
					log.error("ERROR: BillingServer has not been started");
				} catch (LoginFailedRemoteException e){
					log.error("ERROR: Login to BillingServer not successfull!");
				}
	        }
			//TCPSocket
			s = new ServerSocket(tcpport);
			System.out.println("AuctionServer has been started");
			//Thread fuer eingehende Verbindungen
			Thread listen = new Thread(this);
	    	listen.start();
			
	    	
	    	//Interkative Eingabe zum herunterfahren des Servers
			Scanner sc = new Scanner(System.in);
			while(true){
				try{
					if (sc.nextLine().equals("")){
						System.out.println("Interactive command: Shutdown Server");
						
						//Shudown Threadpool
						executor.shutdown();
						
						//Beenden der laufenden Auktionen
						auct.StopAllforShutdown();
						
						//Alle verbundenen Clients disconnecten
						for(int i=0; i<sessionDB.size();i++){
							sessionDB.get(i).sendShutdownNotification();
							sessionDB.get(i).closeStreams();
						}
						try{
							s.close();
						}
						catch (SocketException e){
							System.out.println("Error: Socket closing");
						}
						break;
					}
				}
				catch(NoSuchElementException e){
					log.debug(e.getMessage());
				}
			}
			
		} 
		catch (IOException e) {
			System.out.println("Can't initialize Socketconnection");
		}
		
		
	}
	@Override
	public void run() {
		
			try {
				while (true){
					Socket tempsoc;
					//Accept eingehende Verbindung
					tempsoc = s.accept();
					//Uebergebe Verbindungsdaten an neue Session
					ClientSession newSession = new ClientSession(tempsoc,userdb,auct,sessionDB);
					newSession.setAnalytics(analyticsServ);
					sessionDB.add(newSession);
					//Verwende fuer neue Session einen Thread aus Threadpool
					executor.execute(newSession);
				}
			} catch (IOException e) {
				System.out.println("Server successfully shut down!");
			}		
	}
	
	
	public static void main(String[] args) {
		//Parameterpruefung
		if(args.length==3){
			try{
				//Neue Instanz vom Server mit Parameter
				new Server(Integer.parseInt(args[0]), args[1], args[2]);
			}
			catch (NumberFormatException e){System.out.println("Usage: java Server <server.port> <analytics.bindingName> <billing.bindingName>");}				
			
		}
		else{
			//Usage
			System.out.println("Usage: java Server <server.port> <analytics.bindingName> <billing.bindingName>");
		}
	}

}
